

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JTextArea;

import java.io.IOException;
import java.net.UnknownHostException;

import javax.swing.DefaultListModel;

import javax.swing.JOptionPane;

import javax.swing.JScrollPane;

import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;


public class BirdsongClientDummy implements BirdsongClient {
	private JFrame janela = new JFrame("BirdSong");
	private JFrame janelaMensagens = new JFrame("Escrever Mensagens");

	private JPanel painelConnectados = new JPanel();
	private JPanel painelMensagens = new JPanel();
	private JPanel painelExtra = new JPanel();
	private JPanel painelFollow = new JPanel();
	private JPanel painel1 = new JPanel();

	private JTextArea caixaEscreverMsg = new JTextArea();
	private JLabel conectados = new JLabel("Pessoas Conectadas");
	private DefaultListModel connectedUsersModel = new DefaultListModel();
	private JList listaConectados = new JList(connectedUsersModel);
	private JScrollPane listScrollerConnectados = new JScrollPane(
			listaConectados);
	private DefaultListModel msgRec = new DefaultListModel();
	private JList listaMensagensRecebidas = new JList(msgRec);
	private DefaultListModel msgEviadas = new DefaultListModel();
	private JList listaMensagensEnviadas = new JList(msgEviadas);
	private JButton follow = new JButton("Follow");
	private JButton perfil = new JButton("Perfil");
	private JButton conectarServidor = new JButton();
	private JButton home = new JButton("Home");
	private JButton enviarMensagens = new JButton("Sing it");
	private ClientComm clienteComm;
	private ImageIcon imgon = new ImageIcon("img/onicon.jpg");
	private ImageIcon imgoff = new ImageIcon("img/officon.jpg");
	private ClientSideMessage.Type tipo;
	private Container c = janela.getContentPane();

	/**
	 * The constructor of the client GUI.
	 */
	public BirdsongClientDummy() {
		conectarServidor.setIcon(imgon);
		janela.setResizable(false);

		
		JButton botaoEnviarMsg = new JButton("Enviar");

		/**User messages are sent to the server */
		botaoEnviarMsg.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent arg0) {
				clienteComm.sendBirdsongMessage(caixaEscreverMsg.getText());
				msgEviadas.addElement(caixaEscreverMsg.getText());
				listaMensagensEnviadas.validate();
				janelaMensagens.setVisible(false);
				caixaEscreverMsg.setText("");

			}
		});

		painel1.add(botaoEnviarMsg);

		caixaEscreverMsg.setLineWrap(true);
		Container cMsg = janelaMensagens.getContentPane();
		cMsg.add(caixaEscreverMsg, BorderLayout.CENTER);
		cMsg.add(painel1, BorderLayout.EAST);

		janelaMensagens.setSize(400, 100);

		JLabel legenda = new JLabel("'>' Followed");
		JLabel legenda2 = new JLabel("'<' Follower");

		painelFollow.setLayout(new GridLayout(3, 1));
		painelFollow.add(legenda);
		painelFollow.add(legenda2);
		painelFollow.add(follow);
		follow.setEnabled(false);
		
		/**
		 * After clicking on a user online on list, 
		 * the user can choose follow or unfollow that user
		 * The button changes the name as decided by the user
		 */
		
		follow.addActionListener(new ActionListener() {
			

			@Override
			public void actionPerformed(ActionEvent e) {
				JButton botao = (JButton) e.getSource();
				if (botao.getText() == "Follow") {
					String aux = (String) (listaConectados.getSelectedValue());
					String nickname = normalizedNickname(aux);
					// System.out.println(nickname);
					clienteComm.follow(nickname);
					addFollowed(nickname);
					botao.setEnabled(false);
					botao.setText("Unfollow");
				} else {
					String aux = (String) (listaConectados.getSelectedValue());
					String nickname = normalizedNickname(aux);
					// System.out.println(nickname);
					clienteComm.unfollow(nickname);
					removeFollowed(nickname);
					botao.setEnabled(false);
					botao.setText("Follow");
				}
			}

		});

		painelConnectados.setLayout(new BorderLayout());
		painelConnectados.add(conectados, BorderLayout.NORTH);
		painelConnectados.add(listScrollerConnectados, BorderLayout.CENTER);

		painelConnectados.add(painelFollow, BorderLayout.SOUTH);

		painelMensagens.setLayout(new BorderLayout());
		painelMensagens.add(listaMensagensRecebidas);
		
		/**
		 * Depending on the online user which is selected, 
		 * so is the text that appears on the button (Follow or Unfollow)
		 */

		listaConectados.addListSelectionListener(new ListSelectionListener() {

			@Override
			public void valueChanged(ListSelectionEvent e) {

				follow.setEnabled(true);
				if (((JList) e.getSource()).getSelectedValue() != null) {
					String aux = ((String) ((JList) e.getSource())
							.getSelectedValue()).substring(0, 2);
					// System.out.println(aux);
					if (aux.contains(">")) {
						follow.setText("Unfollow");

					} else {
						follow.setText("Follow");
					}
				}

			}
		});

		/**
		 * Changes the message panel so the user 
		 * can see his sent messages instead of his 
		 * received messages.
		 */
		perfil.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				painelMensagens.remove(listaMensagensRecebidas);
				painelMensagens.add(listaMensagensEnviadas);
				c.validate();
				janela.repaint();

			}
		});

		
		/**
		 * Changes the message panel so the user 
		 * can see his received messages instead of his 
		 * sent messages.
		 */
		home.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				painelMensagens.remove(listaMensagensEnviadas);
				painelMensagens.add(listaMensagensRecebidas);
				c.validate();
				janela.repaint();
			}
		});

		/**
		 * Displays the window to send messages
		 */
		enviarMensagens.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				janelaMensagens.setVisible(true);
			}
		});

		/**
		 * Action listener for Connect Button
		 */
		conectarServidor.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				JButton aux = (JButton) e.getSource();
				if (aux.getIcon().equals(imgon)) {
					String nickname = JOptionPane.showInputDialog("Nickname?");
					String host = null;
//					String host = JOptionPane.showInputDialog("Host?");
					perfil.setEnabled(true);
					home.setEnabled(true);
					enviarMensagens.setEnabled(true);
					
					try {
						aux.setIcon(imgoff);
						clienteComm.connect(host, nickname);

					} catch (UnknownHostException e1) {
						e1.printStackTrace();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				} else {
					aux.setIcon(imgon);
					clienteComm.disconnect();
					perfil.setEnabled(false);
					home.setEnabled(false);
					enviarMensagens.setEnabled(false);
				}

			}

		});

		painelExtra.setLayout(new GridLayout(4, 1));
		painelExtra.add(home);
		painelExtra.add(perfil);
		painelExtra.add(enviarMensagens);
		painelExtra.add(conectarServidor);

		c.add(painelConnectados, BorderLayout.WEST);
		c.add(painelMensagens, BorderLayout.CENTER);
		c.add(painelExtra, BorderLayout.EAST);

		janela.setSize(600, 600);
		janela.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		
		perfil.setEnabled(false);
		home.setEnabled(false);
		enviarMensagens.setEnabled(false);
	}

	public static void main(String[] args) {
		BirdsongClientDummy ig = new BirdsongClientDummy();

		ClientComunication clientComm = new ClientComunication(); // depois alterar para
		// chamar a classe do
		// comunication network
		ig.init();
		ig.start(clientComm);
	}

	private void init() {
		janela.setVisible(true);

	}
	
	/**
	 * method that adds a connected user to a list then sorts it
	 * 
	 * @param nickname
	 */
	private void addConnectedUser(String nickname) { // criar java doc
		connectedUsersModel.addElement(nickname);
		sortConnectedList();
	}
	
	
	private void removeConnectedUser(String nickname) { // criar java doc
		connectedUsersModel.removeElement(normalizedNickname(nickname));
	}

	/**
	 * 
	 * @param nickname
	 * Gets a nickname and adds the respective user to the Followeds
	 * 
	 */
	private void addFollowed(String nickname) { 

		int i = getIndexInModel(nickname);

		String userLista = (String) connectedUsersModel.elementAt(i);

		String user;
		if (userLista.startsWith("<")) {
			user = "<> ".concat(normalizedNickname(userLista));
		} else {
			user = "> ".concat(normalizedNickname(userLista));
		}

		connectedUsersModel.remove(i);
		connectedUsersModel.add(i, user);
		sortConnectedList();
	}
	
	/**
	 * 
	 * @param nickname
	 * Gets a nickname and remove the respective user to de Followeds
	 */
	private void removeFollowed(String nickname) { // criar java doc
		int i = getIndexInModel(nickname);

		String userLista = (String) connectedUsersModel.elementAt(i);

		String user;
		if (userLista.startsWith("<")) {
			user = "< ".concat(normalizedNickname(userLista));
		} else {
			user = normalizedNickname(userLista);
		}

		connectedUsersModel.remove(i);
		connectedUsersModel.add(i, user);
		sortConnectedList();

	}

	/**
	 * 
	 * @param nickname
	 */
	private void addFollower(String nickname) { // seguidor

		int i = getIndexInModel(nickname);
		String userLista = (String) connectedUsersModel.elementAt(i);
		String user;
		if (userLista.startsWith(">")) {
			user = "<> ".concat(normalizedNickname(userLista));
		} else {
			user = "< ".concat(normalizedNickname(userLista));
		}
		connectedUsersModel.remove(i);
		connectedUsersModel.add(i, user);
		sortConnectedList();
	}

	/**
	 * 
	 * @param nickname
	 */
	private void removeFollower(String nickname) { // seguidor
		int i = getIndexInModel(nickname);
		String userLista = (String) connectedUsersModel.elementAt(i);
		String user = userLista.substring(1);

		connectedUsersModel.remove(i);
		connectedUsersModel.add(i, user);
		sortConnectedList();
	}

	/**
	 * 
	 * Method that creates a thread to check if the client has recieved messages on hold and executes a 
	 * different action depending of the message type
	 *
	 */
	private class MessageReader extends Thread{

		@Override
		public void run() {
			while (true) {
				if (clienteComm.hasNextMessage()) {

					ClientSideMessage msg = clienteComm.getNextMessage();
					tipo = msg.getType();

					switch (tipo) {

					case CONNECTED:
						addConnectedUser(msg.getPayload());
						break;

					case DISCONNECTED:
						removeConnectedUser(msg.getPayload());
						break;

					case BIRDSONG_MESSAGE:
						addHomeMsg(msg.getPayload(),
								msg.getSendersNickname());
						break;

					// Seguidor
					case FOLLOWER:
						addFollower(msg.getPayload());
						break;

					case UNFOLLOWER:
						removeFollower(msg.getPayload());
						break;
					case ERROR: janelaErro(msg.getPayload());;
					break;

					}
				}
			}
		}
	}
	
	/**
	 * shows the error to an user
	 * 
	 * @param payload get the error message
	 */
	private void janelaErro(String payload) {
		JOptionPane.showMessageDialog(null, "Erro: " + payload);
	}

	/**
	 * 
	 */
	@Override
	public void start(ClientComm clientComm) {
		this.clienteComm = clientComm;
		MessageReader mr = new MessageReader();
		mr.start();

//		addConnectedUser("< marta");
//		addConnectedUser("hugo");
//		addConnectedUser("<> maria");
//		addConnectedUser("> joao");
//		addConnectedUser("< ze");
//		addConnectedUser("antonia");
//		addConnectedUser("rita");
//		addConnectedUser("> sara");
//		addConnectedUser("<> joana");
//		addConnectedUser("manuel");
//		removeConnectedUser("manuel");
	}

	
	
	 /**
	 * This method sorts the online users, putting in the top of the list, the followed; 
	 * then the followers and lastly the other users
	 */
	 
	public void sortConnectedList() {

		Object[] users = connectedUsersModel.toArray();
		connectedUsersModel.removeAllElements();
		System.out.println(connectedUsersModel);
		System.out.println(users);
		// adicionar os seguidos
		for (int i = 0; i < users.length; i++) {
			if (users[i] != null) {
				String nome = (String) users[i];
				if (nome.contains(">")) {
					connectedUsersModel.addElement(nome);
					users[i] = null;
				}
			}
		}
		// adicionar os seguidores
		for (int i = 0; i < users.length; i++) {
			if (users[i] != null) {
				String nome = (String) users[i];
				if (nome.contains("<")) {
					connectedUsersModel.addElement(nome);
					users[i] = null;
				}
			}

		}

		// adicionar os outros
		for (int i = 0; i < users.length; i++) {
			if (users[i] != null) {
				String nome = (String) users[i];
				if (!nome.contains("<") && !nome.contains(">")) {
					connectedUsersModel.addElement(nome);
					users[i] = null;
				}
			}

		}
	}

	private String normalizedNickname(String aux) {
		String nickname;
		if (aux.contains("<") || aux.contains(">")) {
			nickname = aux.substring(aux.indexOf(" "));
		} else {
			nickname = aux;
		}
		return nickname.trim();
	}


	private int getIndexInModel(String nickname) {
		Object[] users = connectedUsersModel.toArray();
		for (int i = 0; i < users.length; i++) {
			String nome = (String) users[i];
			if (normalizedNickname(nome).equals(nickname)) {
				return i;
			}
		}
		return -1;
	}


	/**
	 * put the message received from other users in DefaltModelList msgRec
	 * 
	 * @param mensagem Message send from the client
	 * @param nome Name of the client
	 */
	private void addHomeMsg(String mensagem, String nome) {
		msgRec.addElement("User: " + nome + " \n said: " + mensagem);
	}

}
